package com.hoshiicloud.common.utils.token;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.hoshiicloud.common.constant.TokenUserFieldEnum;
import io.jsonwebtoken.ExpiredJwtException;

import java.util.Date;

public class JWTUtil {

    // 过期时间三天
    public static final long EXPIRE_TIME = 1440 * 3 * 60 * 1000;

    //accessToken过期时间,单位毫秒
    public static final long ACCESS_TOKEN_EXPIRE_TIME = 10 * 60 * 1000;

    public static String signCompanyRefreshToken(String privateDomain, Long userId, Long companyId, String loginKey, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // TODO 信息使用aes加密
            return JWT.create()
                    .withClaim(TokenUserFieldEnum.PRIVATE_DOMAIN.getName(), privateDomain)
                    .withClaim(TokenUserFieldEnum.USER_ID.getName(), userId)
                    .withClaim(TokenUserFieldEnum.COMPANY_ID.getName(), companyId)
                    .withClaim(TokenUserFieldEnum.LOGIN_KEY.getName(), loginKey)
                    .withClaim(TokenUserFieldEnum.LOGIN_TIME.getName(), System.currentTimeMillis())
                    .sign(algorithm);
        } catch (Exception e) {
            return null;
        }

    }

    /**
     * 获取jwt失效时间
     */
    public Date getExpirationDateFromToken(String token) {
        DecodedJWT jwt = JWTUtil.getDecodedJWT(token);
        return jwt.getExpiresAt();
    }

    /**
     * <pre>
     *  验证token是否失效
     *  true:过期   false:没过期
     * </pre>
     */
    public Boolean isTokenExpired(String token) {
        try {
            final Date expiration = getExpirationDateFromToken(token);
            return expiration.before(new Date());
        } catch (ExpiredJwtException expiredJwtException) {
            return true;
        }
    }

    /**
     * 校验token是否正确
     *
     * @param token  密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String username, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("userName", username)
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * @param token
     * @return com.auth0.jwt.interfaces.DecodedJWT
     * @author: Mr.wu
     * @descripton: 获得token中的信息无需secret解密也能获得
     * @date: 11:35 2019/6/25
     */
    public static DecodedJWT getDecodedJWT(String token) {
        try {
            return JWT.decode(token);
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userName").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static String getUserType(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userType").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static Long getXxId(String token, String idName) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(idName).asLong();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成签名
     *
     * @param userName 用户名
     * @param secret   用户的密码
     * @return 加密的token
     */
    public static String sign(String userName, String realName, String userType, String platformId, String companyId, String secret) {
        try {
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 附带username信息
            // 附带realName信息,
            // TODO 信息使用aes加密
            return JWT.create()
                    .withClaim("userName", userName)
                    .withClaim("realName", realName)
                    .withClaim("userType", userType)
                    .withClaim("platformId", platformId)
                    .withClaim("companyId", companyId)
                    //.withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            return null;
        }
    }

    public static String signMemberRefreshToken(Long memberId, Long companyId, String loginKey, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // TODO 信息使用aes加密
            return JWT.create()
                    .withClaim(TokenUserFieldEnum.COMPANY_ID.getName(), companyId)
                    .withClaim(TokenUserFieldEnum.MEMBER_ID.getName(), memberId)
                    .withClaim(TokenUserFieldEnum.LOGIN_KEY.getName(), loginKey)
                    .withClaim(TokenUserFieldEnum.LOGIN_TIME.getName(), System.currentTimeMillis())
                    .sign(algorithm);
        } catch (Exception e) {
            return null;
        }
    }

    public static String signMemberAccessToken(Long memberId, Long companyId, String secret) {
        try {
            Date date = new Date(System.currentTimeMillis() + ACCESS_TOKEN_EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // TODO 信息使用aes加密
            return JWT.create()
                    .withClaim(TokenUserFieldEnum.COMPANY_ID.getName(), companyId)
                    .withClaim(TokenUserFieldEnum.MEMBER_ID.getName(), memberId)
                    .withClaim(TokenUserFieldEnum.LOGIN_TIME.getName(), System.currentTimeMillis())
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            return null;
        }
    }

    public static String signPlatformAccessToken(Long memberId, Long companyId, Long platformId, String secret) {
        try {
            Date date = new Date(System.currentTimeMillis() + ACCESS_TOKEN_EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(secret);

            // TODO 信息使用aes加密
            return JWT.create()
                    .withClaim(TokenUserFieldEnum.COMPANY_ID.getName(), companyId)
                    .withClaim(TokenUserFieldEnum.MEMBER_ID.getName(), memberId)
                    .withClaim(TokenUserFieldEnum.PLAT_ID.getName(), platformId)
                    .withClaim(TokenUserFieldEnum.LOGIN_TIME.getName(), System.currentTimeMillis())
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            return null;
        }
    }

    public static String signStoreAccessToken(Long memberId, Long companyId, Long storeId, String secret) {
        try {
            Date date = new Date(System.currentTimeMillis() + ACCESS_TOKEN_EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(secret);

            // TODO 信息使用aes加密
            return JWT.create()
                    .withClaim(TokenUserFieldEnum.COMPANY_ID.getName(), companyId)
                    .withClaim(TokenUserFieldEnum.MEMBER_ID.getName(), memberId)
                    .withClaim(TokenUserFieldEnum.STORE_ID.getName(), storeId)
                    .withClaim(TokenUserFieldEnum.LOGIN_TIME.getName(), System.currentTimeMillis())
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 生成签名
     *
     * @param userName 用户名
     * @param secret   用户的密码
     * @return 加密的token
     */
    public static String signAll(String userName, String realName, String userType,
            Long platId, Long storeId, Long companyId, Long userId,
            String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 附带username信息
            // 附带realName信息,
            // TODO 信息使用aes加密
            return JWT.create()
                    .withClaim(TokenUserFieldEnum.USERNAME.getName(), userName)
                    .withClaim(TokenUserFieldEnum.REAL_NAME.getName(), realName)
                    .withClaim(TokenUserFieldEnum.USER_TYPE.getName(), userType)
                    .withClaim(TokenUserFieldEnum.STORE_ID.getName(), storeId)
                    .withClaim(TokenUserFieldEnum.PLAT_ID.getName(), platId)
                    .withClaim(TokenUserFieldEnum.COMPANY_ID.getName(), companyId)
                    .withClaim(TokenUserFieldEnum.USER_ID.getName(), userId)
                    .withClaim(TokenUserFieldEnum.LOGIN_TIME.getName(), System.currentTimeMillis())
                    .sign(algorithm);
        } catch (Exception e) {
            return null;
        }
    }
}
